﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.Video;
namespace ResLibary
{
    public class ResourceLibary : ILibaryHandle
    {
        Thread t;
        private System.Action<LibaryStateObj> UpdateAssetCallback;
        private Dictionary<string, Dictionary<string, ResourceStateObj>> resourceDict;
        private bool _hasLoadAsset = false;
        bool ILibaryHandle.HasLoadAsset { get { return _hasLoadAsset; } }
        public ResourceLibary(System.Action<LibaryStateObj> UpdateAssetCallback)
        {
            this.UpdateAssetCallback = UpdateAssetCallback;
            resourceDict = new Dictionary<string, Dictionary<string, ResourceStateObj>>();

        }
        void ILibaryHandle.InsertLibrary(object body)
        {
            //if (data.GetType().Name != "LibaryResourceSetting")
            //    return;
            //_hasLoadAsset = false;
            //LibaryResourceSetting assetSetting = (LibaryResourceSetting)data;
            //List<List<ResourceSettingStateObj>> list = new List<List<ResourceSettingStateObj>>();
            //list.Add(assetSetting.texture2ds);
            //list.Add(assetSetting.renderTextures);
            //list.Add(assetSetting.movieTextures);
            //list.Add(assetSetting.sprites);
            //list.Add(assetSetting.materials);
            //list.Add(assetSetting.textAssets);
            //list.Add(assetSetting.prefabs);
            //list.Add(assetSetting.audios);
            //list.Add(assetSetting.videos);

            List<object> lbody = (List<object>)body;
            List<List<ResourceSettingStateObj>> list = new List<List<ResourceSettingStateObj>>();
            object[] arr = lbody.ToArray();
            for (int i = 0; i < arr.Length; i++)
            {
                object data = arr[i];
                if (data.GetType().Name != "LibaryResourceSetting")
                    continue;
                LibaryResourceSetting assetSetting = (LibaryResourceSetting)data;
                list.Add(assetSetting.texture2ds);
                list.Add(assetSetting.renderTextures);
                list.Add(assetSetting.movieTextures);
                list.Add(assetSetting.sprites);
                list.Add(assetSetting.materials);
                list.Add(assetSetting.textAssets);
                list.Add(assetSetting.prefabs);
                list.Add(assetSetting.audios);
                list.Add(assetSetting.videos);
                list.Add(assetSetting.fonts);
                list.Add(assetSetting.scriptableObjects);
            }



#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
         InitLibaryAsset(list);
                 }
            else{
         if (t != null)
                t.Abort();
            t = new Thread(InitLibaryAsset);
            t.IsBackground = true;
            t.Start(list);
            }
#else
            if (t != null)
                t.Abort();
            t = new Thread(InitLibaryAsset);
            t.IsBackground = true;
            t.Start(list);
#endif
        }

        void ILibaryHandle.DeleteLiibrary(string _type, string name)
        {
            if (resourceDict.ContainsKey(_type))
            {
                Dictionary<string, ResourceStateObj> objectDict = resourceDict[_type];
                if (objectDict.ContainsKey(name))
                {
                    objectDict.Remove(name);
                }
            }
        }

        private void InitLibaryAsset(object data)
        {
            try
            {
                List<List<ResourceSettingStateObj>> list = (List<List<ResourceSettingStateObj>>)data;
                for (int i = 0; i < list.Count; i++)
                {
                    InitLibaryAssetSetting(list[i]);
                }
            }
            catch (Exception e) { Debug.LogError(e.Message + ":" + e.StackTrace); }
            _hasLoadAsset = true;
        }

        private void InitLibaryAssetSetting(List<ResourceSettingStateObj> list)
        {
            //HashSet<ResourceSettingStateObj> array = new HashSet<ResourceSettingStateObj>(list);
            ResourceSettingStateObj[] array = list.ToArray();
            for (int i = 0; i < array.Length;i++)
            {
                ResourceSettingStateObj item = array[i];
                string _type = item.m_Type;
                if (!resourceDict.ContainsKey(_type))
                    resourceDict[_type] = new Dictionary<string, ResourceStateObj>();
                Dictionary<string, ResourceStateObj> dict = resourceDict[_type];
                ResourceStateObj resobj = new ResourceStateObj(item);

                //if (item.m_ExistStatus == AssetExistStatusEnum.Globle && ResLibaryConfig.ExistTypeNameToType.ContainsKey(resobj.m_Type))
                //{
                //    resobj.m_Asset = Resources.Load(resobj.m_Path, ResLibaryConfig.ExistTypeNameToType[resobj.m_Type]);
                //}

                LibaryStateObj libaryObj = new LibaryStateObj();
                libaryObj.m_Name = item.m_Name;
                libaryObj.m_Status = LibaryStatusEnum.DIR_RESOURCE;
                libaryObj.m_Type = item.m_Type;
#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
                libaryObj.m_Path = resobj.m_AssetPath;
                 }
            else{
           libaryObj.m_Path = resobj.m_ResourcePath;
            }
#else
                libaryObj.m_Path = resobj.m_ResourcePath; 
#endif

                if (UpdateAssetCallback != null)
                    UpdateAssetCallback(libaryObj);
                dict[item.m_Name] = resobj;
                //ResLibaryMgr.Instance.UpdateLibary(libaryObj);
                //if (iterationsPerFrame > 0 && ++iterations % iterationsPerFrame == 0)
                //    yield return 1;
            }
        }
        string ILibaryHandle.GetTextAsset(string objName)
        {
            TextAsset textAsset = ((ILibaryHandle)this).GetObject<TextAsset>(objName);
            if (textAsset != null)
                return textAsset.text;
            return null;
        }

        GameObject GetGameObject(string objName)
        {
            return ((ILibaryHandle)this).GetObject<GameObject>(objName);
        }

        Texture2D ILibaryHandle.GetTexture2d(string objName)
        {
            return ((ILibaryHandle)this).GetObject<Texture2D>(objName);
        }

        RenderTexture GetRenderTexture(string objName)
        {
            return ((ILibaryHandle)this).GetObject<RenderTexture>(objName);
        }

        Sprite ILibaryHandle.GetSprite(string objName)
        {
            return ((ILibaryHandle)this).GetObject<Sprite>(objName);
        }

        Material GetMatiral(string objName)
        {
            return ((ILibaryHandle)this).GetObject<Material>(objName);
        }

        AudioClip GetAudioClip(string objName)
        {
            return ((ILibaryHandle)this).GetObject<AudioClip>(objName);
        }

        VideoClip GetVideoClip(string objName)
        {
            return ((ILibaryHandle)this).GetObject<VideoClip>(objName);
        }

        MovieTexture GetMovieTexture(string objName)
        {
            return ((ILibaryHandle)this).GetObject<MovieTexture>(objName);
        }

        T ILibaryHandle.GetObject<T>(string objName)
        {
            string _type = "";
            if (!ResLibaryConfig.TryGetTypeName<T>(out _type))
                return null;
            return (T)((ILibaryHandle)this).GetUnityObject(_type, objName);
        }

        UnityEngine.Object ILibaryHandle.GetUnityObject(string _type, string objName)
        {
            if (resourceDict.ContainsKey(_type))
            {
                Dictionary<string, ResourceStateObj> _Dict = resourceDict[_type];
                ResourceStateObj stateObj;
                _Dict.TryGetValue(objName, out stateObj);
                if (stateObj != null)
                {
                    if (stateObj.m_Asset == null)
                    {

#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
                if (_type == ResLibaryConfig.ExistType[LibaryTypeEnum.
                            LibaryType_Sprite])
                        {
                            string[] sprPaths = stateObj.m_AssetPath.Split(':');
                            UnityEditor.TextureImporter textureImporter = UnityEditor.TextureImporter.GetAtPath(stateObj.m_AssetPath) as UnityEditor.TextureImporter;
                            if (sprPaths.Length == 2 && textureImporter.textureType == UnityEditor.TextureImporterType.Sprite)
                            {
                                int sprIndex = 0;
                                if (int.TryParse(sprPaths[1], out sprIndex))
                                {
                                    UnityEngine.Object[] sprs = UnityEditor.AssetDatabase.LoadAllAssetsAtPath(sprPaths[0]);
                                    stateObj.m_Asset = sprs == null || sprs.Length == 0 ? null : sprs[Mathf.Min(sprIndex, sprs.Length - 1)];
                                }
                                else
                                    return null;
                            }
                            else
                                return null;
                           
                        }
                        else
                            stateObj.m_Asset =  UnityEditor.AssetDatabase.LoadMainAssetAtPath(stateObj.m_AssetPath);
                 }
            else{
          if (_type == ResLibaryConfig.ExistType[LibaryTypeEnum.
                            LibaryType_Sprite])
                        {
                            string[] sprPaths = stateObj.m_ResourcePath.Split(':');
                            if (sprPaths.Length == 2)
                            {
                                int sprIndex = 0;
                                if (int.TryParse(sprPaths[1], out sprIndex))
                                {
                                    Sprite[] sprs = Resources.LoadAll<Sprite>(sprPaths[0]);
                                    stateObj.m_Asset = sprs == null || sprs.Length == 0 ? null : sprs[Mathf.Min(sprIndex, sprs.Length - 1)];
                                }
                                else
                                {
                                    stateObj.m_Asset = Resources.Load(stateObj.m_ResourcePath, ResLibaryConfig.ExistTypeNameToType[_type]);
                                }
                            }
                            else
                            {
                                stateObj.m_Asset = Resources.Load(stateObj.m_ResourcePath, ResLibaryConfig.ExistTypeNameToType[_type]);
                            }
                        }
                        else
                            stateObj.m_Asset = Resources.Load(stateObj.m_ResourcePath, ResLibaryConfig.ExistTypeNameToType[_type]);
                }
#else

                        if (_type == ResLibaryConfig.ExistType[LibaryTypeEnum.
                            LibaryType_Sprite])
                        {
                            string[] sprPaths = stateObj.m_ResourcePath.Split(':');
                            if (sprPaths.Length == 2)
                            {
                                int sprIndex = 0;
                                if (int.TryParse(sprPaths[1], out sprIndex))
                                {
                                    Sprite[] sprs = Resources.LoadAll<Sprite>(sprPaths[0]);
                                    stateObj.m_Asset = sprs == null || sprs.Length == 0 ? null : sprs[Mathf.Min(sprIndex, sprs.Length - 1)];
                                }
                                else
                                {
                                    stateObj.m_Asset = Resources.Load(stateObj.m_ResourcePath, ResLibaryConfig.ExistTypeNameToType[_type]);
                                }
                            }
                            else
                            {
                                stateObj.m_Asset = Resources.Load(stateObj.m_ResourcePath, ResLibaryConfig.ExistTypeNameToType[_type]);
                            }
                        }
                        else
                            stateObj.m_Asset = Resources.Load(stateObj.m_ResourcePath, ResLibaryConfig.ExistTypeNameToType[_type]);
#endif

                    }
                    UnityEngine.Object t = stateObj.m_Asset;
                    if (stateObj.m_ExistStatus == AssetExistStatusEnum.Once)
                        stateObj.m_Asset = null;
                    if (t != null && stateObj.m_ExistStatus == AssetExistStatusEnum.Quote)
                        stateObj.m_Quote++;
                    return t;
                }
            }
            return null;
        }

        LibaryExistStatusEnum ILibaryHandle.TryGetObject(LibaryTypeEnum libaryTypeEnum, string objName, out object data)
        {
            data = ((ILibaryHandle)this).GetUnityObject(ResLibaryConfig.ExistType[libaryTypeEnum], objName);
            LibaryExistStatusEnum libaryExistStatusEnum = LibaryExistStatusEnum.LibaryExistStatus_UnityEngineObject;
            return libaryExistStatusEnum;
        }

        void ILibaryHandle.releaseObj(LibaryTypeEnum libaryTypeEnum, string objName)
        {
            string _type = ResLibaryConfig.ExistType[libaryTypeEnum];
            ((ILibaryHandle)this).releaseObj(_type, objName);
        }

        void ILibaryHandle.releaseObj(string _type, string objName)
        {
            if (resourceDict.ContainsKey(_type))
            {
                Dictionary<string, ResourceStateObj> _Dict = resourceDict[_type];
                ResourceStateObj stateObj;
                _Dict.TryGetValue(objName, out stateObj);
                if (stateObj != null && stateObj.m_ExistStatus == AssetExistStatusEnum.Quote)
                {
                    stateObj.m_Quote = Mathf.Max(0, stateObj.m_Quote - 1);
                    if (stateObj.m_Quote == 0)
                        stateObj.m_Asset = null;
                }
            }
        }

        void ILibaryHandle.releaseObj(UnityEngine.Object obj)
        {
            string _type = obj.GetType().Name;
            ((ILibaryHandle)this).releaseObj(_type, obj.name);
        }

        void ILibaryHandle.releaseScene()
        {
            foreach (var dict in resourceDict.Values)
            {
                List<ResourceStateObj> list = new List<ResourceStateObj>(dict.Values);
                HashSet<ResourceStateObj> array = new HashSet<ResourceStateObj>(list);
                foreach (var stateObj in array)
                {
                    if (stateObj != null && stateObj.m_Asset != null)
                    {
                        if (stateObj.m_Asset != null && stateObj.m_ExistStatus == AssetExistStatusEnum.Scene)
                        {
                            stateObj.m_Asset = null;
                        }

                    }
                }
            }
            Resources.UnloadUnusedAssets();
        }

        void ILibaryHandle.releaseAll()
        {
            if (t != null && t.IsAlive)
            {
                t.Abort();
            }
            resourceDict.Clear();
#if UNITY_EDITOR
                if (!ResLibaryConfig.isPlaying)
                {
                 }
            else{
            Resources.UnloadUnusedAssets();
            }
#else
            Resources.UnloadUnusedAssets();
#endif
        }
    }
}